package def;

import java.io.File;
import java.util.ArrayList;
import java.util.Hashtable;
import java.util.List;

import setting.BioNLPSettings;
import util.io.FileUtil;
import abs.Document;
import abs.syn.Dependency;
import abs.syn.Parse;
import abs.syn.SynTree;

public class BioNLPDocument extends Document {
	public Hashtable<String, Argument> tspans = null;
	public Hashtable<String, Event> events = null;
	public ArrayList<Protein> proteins = null;
	public Parse[] parses = null;
	public ArrayList<String> equiv = null; 
	public boolean valid = true;
	public AbstractText aText = null;

	public String getText(int start, int end){
		if (aText!=null)
			return aText.text.substring(start, end);
		else
			return null;

	}

	public int getSentenceIdByPos(int start){
		if (aText != null){
			return aText.getSentenceIdByPos(start);
		}
		return -1;
	}
	/**
	 * 
	 * @return
	 */
	public Argument getArgById(String id){
		if (id.startsWith("E")){
			if (events != null)
				return events.get(id);
		}
		else if (id.startsWith("T")){
			if (tspans !=null)
				return tspans.get(id);
		}
		else{
			System.err.println("getArgById@BioNLPDocument: Not supported for "+id);
			return null;
		}
		return null;
	}

	public BioNLPDocument(String path, String filePrefix){
		Argument.clear();
		fileId = filePrefix;

		
		

		/*Hashtable<String, Argument>*/ tspans = new Hashtable<String,Argument>();

		// read a1
		String[] lines = FileUtil.getTextFromFile(path+filePrefix+".a1").split("\n");
		if (lines.length==1 && lines[0].trim().length()==0){
			
		}
		else{
		for (String line: lines){

			String[] items = line.split("\t");
			tspans.put(items[0], Argument.parse(line));
			String[] items2 = items[1].split(" ");
//			if (!text.substring(Integer.parseInt(items2[1]), Integer.parseInt(items2[2])).equals(items[2]))
//			{
//				System.err.println("ERROR!!"+text.substring(Integer.parseInt(items2[1]), Integer.parseInt(items2[2]))+"::"+items[2]+"::");
//			}
		}
		}
		proteins = new ArrayList<Protein>(tspans.size());
		for (Argument arg: tspans.values()){
			proteins.add((Protein)arg);
		}
		
		// read text
		text = new AbstractText(path + filePrefix+".txt", this);
		aText = (AbstractText)text;
		if (proteins.size() == 0)
			return;
		
		events = new Hashtable<String, Event>();
		equiv = new ArrayList<String>();
		// read a2
		if (new File(path+filePrefix+BioNLPSettings.getValue("EventAnnotationSuffix")).exists()){
			lines = FileUtil.getTextFromFile(path+filePrefix+BioNLPSettings.getValue("EventAnnotationSuffix")).split("\n");
			for (String line: lines){
				if (line.startsWith("T")){
					String[] items = line.split("\t");
					Argument arg = Argument.parse(line);
					if (arg!=null ){
						tspans.put(items[0], arg);
					}
					else{
						if (!line.contains("Entity"))
							System.err.println(arg +" IN @@ "+ line);
					}
					String[] items2 = items[1].split(" ");
					if (!text.substring(Integer.parseInt(items2[1]), Integer.parseInt(items2[2])).equals(items[2]))
					{
						System.err.println("ERROR!!"+text.substring(Integer.parseInt(items2[1]), Integer.parseInt(items2[2]))+"::"+items[2]+"::");
					}
				}
				else if (line.startsWith("E")){
					Event event = (Event)Argument.parse(line);
					events.put(event.getId(), (Event)event);
				}
				else if (line.startsWith("*")){
					//* Equiv T25 T26
					equiv.add(line.substring(line.indexOf("\t")+1));
				}
				else{
					
				}
			}

			//		Argument.debugPrintArgs(System.err);
			// merge events
			for (Event event: events.values())
			{
				if (event.getTspan() == null){
					Event et = (Event)Argument.find(event.tid);
					if (et!=null){
						//					System.err.println(event.tid+"@@"+et.tspan);
						event.merge(et);
						//					System.err.println(event+" afterwards");
					}else{
						//					System.err.println("can't find tspan for event");
					}
				}
				event.tspan.fileId = filePrefix;
				// check if any argument missing
				checkArg(event);
			}
		}


		// parse
		parses = new Parse[((AbstractText)text).lines.length];
		String[] parseTexts = FileUtil.getTextFromFile("data/BioNLP09/"+BioNLPSettings.getValue("parsePath") + "/" + "pstree/"+fileId+".pstree").split("\n");
		String[] depTexts = FileUtil.getTextFromFile("data/BioNLP09/"+BioNLPSettings.getValue("parsePath") + "/"+ "dep/" + fileId +".dep").split("\n\n");
		int numSent = ((AbstractText)text).lines.length;
		if (numSent != parseTexts.length /*|| numSent!= depTexts.length*/){
			System.err.println("["+filePrefix+"] nums don't match. "+ numSent +" "+parseTexts.length +" "+ depTexts.length);
			for (int i = 0; i < numSent; i++){
				System.err.println( ((AbstractText)text).lines[i]+"@@");
			}
			valid = false;
			return ;
		}
		else{
			if (parses.length != numSent){
				System.err.println("parses num not match "+parses.length +"   "+ numSent);
				valid = false;
				return ;
			}
			else{
				// fix missing deps for one sentence
				if (parseTexts.length!=depTexts.length){
					String[] depTexts2 = new String[numSent];
					int idx = 0;
					for (int i = 0; i < depTexts.length; i++){
						if (depTexts[i].startsWith("\n")){
							depTexts2[idx++] = "";
							depTexts2[idx++] = depTexts[i];
						}
						else{
							depTexts2[idx++] = depTexts[i];
						}
					}
					depTexts = depTexts2;
				}
				// END fix***
				
				for (int i = 0; i < numSent; i++){
					SynTree root = SynTree.buildFromString(parseTexts[i]);
					List<Dependency> deps = Dependency.buildListFromString(depTexts[i]);
					//				root.print(System.out);
					//				System.out.println();
					//				System.out.println(parseString.replaceAll("\\s+",""));
					//				String line = "Interestingly, Nmi lacks an intrinsic transcriptional activation domain; instead, Nmi enhances the association of CBP/p300 coactivator proteins with Stat1 and Stat5, and together with CBP/p300 can augment IL-2- and IFNgamma-dependent transcription.";
					Parse parse = new Parse(((AbstractText)text).lines[i], root, deps);
					if (parse.startPos == null){
						valid = false;
						break;
					}
					try{
						parses[i] = parse;
					}catch(Exception e) {
						System.err.println(parses.length+"  "+i + "  "+numSent);
						e.printStackTrace();
						System.exit(-1);
					}
				}
				System.out.println(filePrefix+ "processed");
			}
		}
	}


	private static void checkArg(Event event) {
		for (int i = 0; i < event.args.size(); i++){
			Argument arg = event.args.get(i);
			if (arg.getTspan() == null){
				Argument realOne = Argument.find(arg.getId());
				if (realOne !=null){
					event.args.remove(i);
					event.args.add(i, realOne);
				}else{
					System.err.println("checkArg@RequireCoref can't find real arg::"+arg.getId()+"::"+event.getId()+" in "+event.tspan.fileId);
					Argument.debugPrintArgs(System.err);
				}
			}
			if (arg instanceof Event){
				checkArg((Event)arg);
			}
		}
	}

	/**
	 * 
	 * @param filePrefix
	 */
	public void printResult(String path, String filePrefix){
		//TODO
		printResult(filePrefix, "");
	}
	/**
	 * 
	 * @param filePrefix
	 * @param task
	 */
	public void printResult(String path, String filePrefix, String task){
		// if file already exists, return 
		String filename  =path+filePrefix+".a2";
		if (task.length()>0){
			filename+="."+task;
		}
		if (new File(filename).exists()){
			System.err.println("printResult@BioNLPDocument : error  "+filename+" already existed");
		}

		StringBuilder sb = new StringBuilder();
		// print out events, tspans
		for (Event e : events.values()){
			sb.append(e.tspan+"\n");
			sb.append(e.getId()+"\t"+e.eventType+":"+e.tspan.tid);
			int idxTheme = 1;
			for (int i = 0; i < e.args.size(); i++){
				if (e.types.get(i) == ArgType.Theme){
					if (idxTheme == 1)
						sb.append(" "+e.types.get(i)+":"+e.args.get(i));
					else
						sb.append(" "+e.types.get(i)+idxTheme+":"+e.args.get(i));
					idxTheme++;
				}
			}
			sb.append("\n");
		}
		FileUtil.writeTextToFile(sb.toString(), filename);
	}
}
